//-----------------------------------------------------------------------------
//															Matrix44 class
//-----------------------------------------------------------------------------
inline Matrix44::Matrix44()
{
	//SetIdentity();
}

inline Matrix44::Matrix44(const Matrix44& m)
: _11(m._11), _12(m._12), _13(m._13), _14(m._14)
, _21(m._21), _22(m._12), _23(m._23), _24(m._24)
, _31(m._31), _32(m._12), _33(m._33), _34(m._34)
, _41(m._41), _42(m._12), _43(m._43), _44(m._44)
{
	
}

inline Matrix44::operator float* ()
{
	return &_11;
}

inline Matrix44::operator const float* () const
{
	return &_11;
}

inline Matrix44& Matrix44::operator= (const Matrix44& rhs)
{
	if (this != &rhs)
	{
		for (uint i = 0; i < 4; ++i)
		{
			for (uint j = 0; j < 4; ++j)
				m[i][j] = rhs.m[i][j];
		}
	}
	return *this;
}

inline Matrix44& Matrix44::operator+=(const Matrix44& rhs)
{
	for (uint i = 0; i < 4; ++i)
		for (uint j = 0; j < 4; ++j)
			m[i][j] += rhs.m[i][j];

	return *this;
}

inline Matrix44& Matrix44::operator-=(const Matrix44& rhs)
{
	for (uint i = 0; i < 4; ++i)
		for (uint j = 0; j < 4; ++j)
			m[i][j] -= rhs.m[i][j];

	return *this;
}

inline Matrix44& Matrix44::operator*=(const Matrix44& rhs)
{
	Matrix44 copy(*this);
	SetZero();
	for (uint i = 0; i < 4; ++i)
		for (uint j = 0; j < 4; ++j)
			for (uint k = 0; k < 4; ++k)
				m[i][j] += copy.m[i][k] * rhs.m[k][j];

	return *this;
}

inline Matrix44& Matrix44::operator*= (float rhs)
{
	for (uint i = 0; i < 4; ++i)
	{
		for (uint j = 0; j < 4; ++j)
			m[i][j] *= rhs;
	}
	return *this;
}

inline Matrix44&	Matrix44::operator/= (float rhs)
{
	for (uint i = 0; i < 4; ++i)
	{
		for (uint j = 0; j < 4; ++j)
			m[i][j] /= rhs;
	}
	return *this;
}

inline Matrix44 Matrix44::operator+ () const
{
	return *this;
}

inline Matrix44 Matrix44::operator- () const
{
	return -1 * *this;
}

inline Matrix44 Matrix44::operator+ (const Matrix44& rhs) const
{
	Matrix44 result(*this);
	result += rhs;
	return result;
}

inline Matrix44 Matrix44::operator- (const Matrix44& rhs) const
{
	Matrix44 result(*this);
	result -= rhs;
	return result;
}

inline Matrix44 Matrix44::operator* (const Matrix44& rhs) const
{
	Matrix44 result(*this);
	result *= rhs;
	return result;
}

inline Matrix44 Matrix44::operator* (float rhs) const
{
	Matrix44 result(*this);
	result *= rhs;
	return result;
}

inline Matrix44 Matrix44::operator/ (float rhs) const
{
	Matrix44 result(*this);
	result /= rhs;
	return result;
}

inline Matrix44 operator* (float number, const Matrix44& matrix)
{
	Matrix44 result(matrix);
	for (uint i = 0; i < 4; ++i)
	{
		for (uint j = 0; j < 4; ++j)
			result.m[i][j] *= number;
	}
	return result;
}

inline bool Matrix44::operator== (const Matrix44& rhs) const
{
	for (uint i = 0; i < 4; ++i)
	{
		for (uint j = 0; j < 4; ++j)
		{
			if (m[i][j] != rhs.m[i][j])
				return false;
		}
	}
	return true;
}

inline bool Matrix44::operator!= (const Matrix44& rhs) const
{
	return !(*this == rhs);
}

inline void Matrix44::SetZero()
{
	memset(m, 0, sizeof(m));
}

inline void Matrix44::SetIdentity()
{
	SetZero();
	_11 = _22 = _33 = _44 = 1.0f;
}

inline void Matrix44::SetPerspective(float z_near, float z_far, float fov, float aspect)
{
	//	D3D
	/*float h = 1.0f/tan(deg2rad(fov) * 0.5f);
	float Q = z_far/(z_far - z_near);

	SetZero();
	_11 = h / aspect;
	_22 = h;
	_33 = Q;
	_34 = 1;
	_43 = -Q*z_near;*/

	//	OpenGL
	float h = 1.0f/tan(deg2rad(fov) * 0.5f);
	float neg_depth = z_near - z_far;

	SetZero();
	_11 = h / aspect;
	_22 = h;
	_33 = (z_far + z_near)/neg_depth;
	_34 = -1;
	_43 = 2.0f*(z_near * z_far)/neg_depth;
}

inline void Matrix44::SetLookAt(const Vec3& eye_position, const Vec3& look_target, const Vec3& up_axis)
{
	/*zaxis = normal(At - Eye)
	xaxis = normal(cross(Up, zaxis))
	yaxis = cross(zaxis, xaxis)

	xaxis.x           yaxis.x           zaxis.x          0
	xaxis.y           yaxis.y           zaxis.y          0
	xaxis.z           yaxis.z           zaxis.z          0
	-dot(xaxis, eye)  -dot(yaxis, eye)  -dot(zaxis, eye)  l*/

	Vec3 zaxis = (look_target - eye_position).normalized();
	Vec3 xaxis = (up_axis ^ zaxis).normalized();
	Vec3 yaxis = zaxis ^ xaxis;

	_11 = xaxis.x;	_12 =yaxis.x;		_13 = zaxis.x;	_14 = 0;
	_21 = xaxis.y;	_22 = yaxis.y;	_23 = zaxis.y;	_24 = 0;
	_31 = xaxis.z;	_32 = yaxis.z;	_33 = zaxis.z;	_34 = 0;

	_41 = -(xaxis * eye_position);
	_42 = -(yaxis * eye_position);
	_43 = -(zaxis * eye_position);
	_44 = 1;
}